/*!
 * \file SignalHook.hpp
 * \project WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief 信号处理钩子工具
 * 
 * \details 本文件实现了跨平台的信号处理机制，用于捕获和处理系统信号。
 *          主要功能包括：
 *          - 统一的信号处理接口
 *          - 跨平台信号兼容性处理（Windows/Linux）
 *          - 异常信号的堆栈跟踪
 *          - 优雅的程序终止处理
 *          - 可配置的日志回调机制
 *          
 *          支持的信号类型：
 *          - 中断信号（SIGINT、SIGTERM等）
 *          - 异常信号（SIGSEGV、SIGFPE等）
 *          - 用户定义信号（SIGUSR1、SIGUSR2等）
 *          - 系统控制信号（SIGSTOP、SIGCONT等）
 */
#pragma once
#include <signal.h>
#include "./StackTracer/StackTracer.h"

/*!< 全局信号日志回调函数指针，用于输出信号处理信息 */
TracerLogCallback g_cbSignalLog = NULL;

/*!
 * \brief 信号处理函数
 * 
 * \details 统一的信号处理入口函数，根据不同的信号类型执行相应的处理逻辑：
 *          1. 中断信号：记录日志并优雅退出
 *          2. 异常信号：记录日志、打印堆栈跟踪并退出
 *          3. 控制信号：记录日志并继续执行或退出
 *          4. 用户信号：记录日志、打印堆栈跟踪并退出
 *          
 *          该函数提供跨平台的信号处理兼容性，在Windows和Linux系统上
 *          都能正确处理相应的信号类型。
 * 
 * \param signum 接收到的信号编号
 * 
 * \note 该函数会根据信号类型决定是否退出程序
 * \warning 异常信号会导致程序立即退出
 */
void handle_signal(int signum)
{
	static char buf[64] = { 0 };
	memset(buf, 0, 64);
	switch (signum)
	{
#ifdef _WIN32
	// Windows平台信号处理
	case SIGINT:          // 中断信号 - 用户按Ctrl+C
	case SIGBREAK:        // 中断信号 - 用户按Ctrl+Break
		g_cbSignalLog("app interrupted");
		break;
	case SIGTERM:         // 终止信号 - 软件终止信号
		g_cbSignalLog("app terminated");
		break;
	case SIGILL:          // 非法指令异常 - 无效的函数映像
	case SIGFPE:          // 浮点异常 - 浮点运算错误
	case SIGSEGV:         // 段错误 - 内存访问违规
	case SIGABRT:         // 异常终止 - abort()调用触发
	case SIGABRT_COMPAT:  // SIGABRT兼容版本 - 与其他平台兼容
		sprintf(buf, "app stopped by signal %d", signum);
		g_cbSignalLog(buf);
		print_stack_trace(g_cbSignalLog);  // 打印堆栈跟踪
		exit(signum);
		break;
#else
	// Linux/Unix平台信号处理
	
	// 可忽略的信号 - 记录日志但不退出程序
	case SIGURG:       // 紧急数据信号 - socket上有紧急数据
	case SIGCONT:      // 继续执行信号 - 从停止状态继续
	case SIGCHLD:      // 子进程状态改变信号
	case SIGIO:        // I/O可用信号 - 描述符上可进行I/O操作
	case SIGWINCH:     // 窗口大小改变信号
		sprintf(buf, "app discard signal %d", signum);
		g_cbSignalLog(buf);
		break;
		
	// 停止进程的信号
	case SIGSTOP:      // 停止进程 - 无法捕获或忽略
	case SIGTSTP:      // 停止进程 - 键盘产生的停止信号
	case SIGTTIN:      // 停止进程 - 后台进程尝试从控制终端读取
	case SIGTTOU:      // 停止进程 - 后台进程尝试写入控制终端
		sprintf(buf, "app stopped by signal %d", signum);
		g_cbSignalLog(buf);
		exit(signum);
		
	// 中断信号
	case SIGINT:       // 终止进程 - 中断程序（Ctrl+C）
		g_cbSignalLog("app interrupted");
		break;
	case SIGTERM:      // 终止进程 - 软件终止信号
		g_cbSignalLog("app terminated");
		break;
	case SIGKILL:      // 终止进程 - 强制杀死程序
		g_cbSignalLog("app killed");
		exit(signum);
		
	// 其他终止信号
	case SIGHUP:       // 终止进程 - 终端线路挂起
	case SIGPIPE:      // 终止进程 - 向无读者的管道写入
	case SIGALRM:      // 终止进程 - 实时定时器超时
	case SIGXCPU:      // 终止进程 - CPU时间限制超出
	case SIGXFSZ:      // 终止进程 - 文件大小限制超出
	case SIGVTALRM:    // 终止进程 - 虚拟定时器超时
	case SIGPROF:      // 终止进程 - 性能分析定时器超时
		sprintf(buf, "app terminated by signal %d", signum);
		g_cbSignalLog(buf);
		print_stack_trace(g_cbSignalLog);  // 打印堆栈跟踪
		exit(signum);
		
	// 用户定义信号
	case SIGUSR1:      // 终止进程 - 用户定义信号1
	case SIGUSR2:      // 终止进程 - 用户定义信号2
		sprintf(buf, "app caught user defined signal %d", signum);
		g_cbSignalLog(buf);
		print_stack_trace(g_cbSignalLog);  // 打印堆栈跟踪
		exit(signum);
		
	// 创建核心转储的信号
	case SIGQUIT:      // 创建核心映像 - 退出程序
	case SIGILL:       // 创建核心映像 - 非法指令
	case SIGTRAP:      // 创建核心映像 - 跟踪陷阱
	case SIGABRT:      // 创建核心映像 - 异常终止程序
	case SIGFPE:       // 创建核心映像 - 浮点异常
	case SIGBUS:       // 创建核心映像 - 总线错误
		g_cbSignalLog("bus error");
		print_stack_trace(g_cbSignalLog);  // 打印堆栈跟踪
		exit(signum);
	case SIGSEGV:      // 创建核心映像 - 段错误
		g_cbSignalLog("segmentation violation");
		print_stack_trace(g_cbSignalLog);  // 打印堆栈跟踪
		exit(signum);
	case SIGSYS:       // 创建核心映像 - 调用不存在的系统调用
		sprintf(buf, "app caught unexpected signal %d", signum);
		g_cbSignalLog(buf);
		print_stack_trace(g_cbSignalLog);  // 打印堆栈跟踪
		exit(signum);
#endif // _WIN32
	default:
		// 未知信号处理
		sprintf(buf, "app caught unknown signal %d, signal ignored", signum);
		g_cbSignalLog(buf);
	}
}

/*!
 * \brief 安装信号处理钩子
 * 
 * \details 为系统中所有可用的信号安装统一的处理函数。
 *          该函数会遍历所有信号编号（1到NSIG-1），并为每个信号
 *          注册handle_signal函数作为处理器。
 *          
 *          安装后的效果：
 *          - 所有信号都会被统一处理
 *          - 异常信号会触发堆栈跟踪
 *          - 程序崩溃时能够记录详细的错误信息
 *          - 提供优雅的程序退出机制
 * 
 * \param cb 日志回调函数指针，用于输出信号处理信息
 * 
 * \note 该函数应该在程序启动时尽早调用
 * \warning 某些信号（如SIGKILL、SIGSTOP）无法被捕获或忽略
 */
void install_signal_hooks(TracerLogCallback cb)
{
	// 设置全局日志回调函数
	g_cbSignalLog = cb;
	
	// 为所有信号安装处理函数
	for (int s = 1; s < NSIG; s++)
	{
		signal(s, handle_signal);
	}
}

